#include <stdlib.h>
#include <stdio.h>

#define private static
#define public

#define RECORD_COUNT 4

#define FILE_NAME "work.txt"
#define INPUT_FILE_NAME FILE_NAME
#define OUTPUT_FILE_NAME FILE_NAME

typedef FILE *File;
typedef char* String;

/* 职员对象 */

typedef struct _Employee {
  char name[8];
  int age;
  int salary;
} *Employee;

typedef Employee (*EmployeeFn)(Employee, File);

private Employee employee_free(Employee employee, File stream) {
  free(employee);
  return NULL;
}

private Employee employee_read(Employee employee, File istream) {
  employee = (Employee) calloc(1, sizeof(struct _Employee));
  if (employee == NULL) {
    fprintf(stderr, "employee_read: out of memory\n");
    exit(EXIT_FAILURE);
  }
  if (fscanf(istream, "%s%d%d", employee->name, &employee->age, &employee->salary) != 3) {
    employee_free(employee, NULL);
    return NULL;
  }
  return employee;
}

private Employee employee_print(Employee employee, File ostream) {
  fprintf(ostream, "%s %d %d\n", employee->name, employee->age, employee->salary);
  return employee;
}

private Employee employee_adjust_salary(Employee employee, File stream) {
  if (employee->salary < 30000) {
    employee->salary += 3000;
  }
  return employee;
}

/* 职员列表对象 */

typedef Employee* Employees;

private Employees employees_map(Employees employees, File stream, EmployeeFn fn) {
  for (int index = 0; index < RECORD_COUNT; index++) {
    employees[index] = fn(employees[index], stream);
  }
  return employees;
}

private Employees employees_read(File istream) {
  Employees employees = (Employees) calloc(RECORD_COUNT, sizeof(Employee));
  if (employees == NULL) {
    fprintf(stderr, "employees_read: out of memory\n");
    exit(EXIT_FAILURE);
  }
  return employees_map(employees, istream, employee_read);
}

public void employees_print(Employees employees, File ostream) {
  employees_map(employees, ostream, employee_print);
}

public void employees_adjust_salary(Employees employees) {
  employees_map(employees, NULL, employee_adjust_salary);
}

public void employees_free(Employees employees) {
  employees_map(employees, NULL, employee_free);
  free(employees);
}

/* I/O层 */

private File file_open(String filename, String mode) {
  File stream = fopen(filename, mode);
  if (stream == NULL) {
    fprintf(stderr, "Cannot open %s with %s mode.\n", filename, mode);
    exit(EXIT_FAILURE);
  }
  return stream;
}

public Employees employees_input(String filename) {
  File istream = file_open(filename, "r");
  Employees employees = employees_read(istream);
  fclose(istream);
  return employees;
}

public void employees_output(Employees employees, String filename) {
  File ostream = file_open(filename, "w");
  employees_print(employees, ostream);
  fclose(ostream);
}

/* 应用层 */

int main(void) {
  Employees employees = employees_input(INPUT_FILE_NAME); /* 从文件读入 */
  employees_print(employees, stdout);                     /* 1. 输出到屏幕 */
  employees_adjust_salary(employees);                     /* 2. 调整薪资 */
  employees_print(employees, stdout);                     /* 3. 输出调整后的结果 */
  employees_output(employees, OUTPUT_FILE_NAME);          /* 4. 保存到文件 */
  employees_free(employees);                              /* 释放资源 */

  return EXIT_SUCCESS;
}
